import copy
import uuid
from typing import List, Dict


# -------------------------- 1. 辅助类：订单相关子对象（引用类型） --------------------------
class Product:
    """商品类（引用类型成员）"""

    def __init__(self, product_id: str, name: str, price: float, stock: int):
        self.product_id = product_id
        self.name = name
        self.price = price
        self.stock = stock  # 库存（可变属性，需深克隆）

    def __str__(self):
        return f"Product(product_id={self.product_id}, name={self.name}, price={self.price}, stock={self.stock})"


class Address:
    """收货地址类（引用类型成员）"""

    def __init__(self, user_id: str, province: str, city: str, detail: str):
        self.user_id = user_id
        self.province = province
        self.city = city
        self.detail = detail

    def __str__(self):
        return f"Address(province={self.province}, city={self.city}, detail={self.detail})"


# -------------------------- 2. 抽象原型：订单原型接口 --------------------------
class OrderPrototype:
    """订单抽象原型（定义克隆接口）"""

    def clone(self, **kwargs) -> "OrderPrototype":
        """
        克隆订单并修改差异属性
        :param kwargs: 差异属性（如order_id、user_id、total_amount）
        :return: 新订单实例
        """
        raise NotImplementedError("具体原型必须实现clone方法")

    def init_complex_data(self, user_id: str, product_ids: List[str]):
        """模拟复杂初始化逻辑：查询用户地址、商品信息（仅原型初始化时执行一次）"""
        # 1. 模拟查询用户地址（数据库操作）
        self.address = Address(
            user_id=user_id,
            province="广东省",
            city="深圳市",
            detail="南山区科技园路1号"
        )
        # 2. 模拟查询商品信息（数据库操作）
        self.products = []
        product_db = {
            "p1001": Product("p1001", "iPhone 15", 6999.0, 100),
            "p1002": Product("p1002", "AirPods Pro", 1799.0, 200),
            "p1003": Product("p1003", "MacBook Pro", 13999.0, 50)
        }
        for pid in product_ids:
            if pid in product_db:
                self.products.append(product_db[pid])
        # 3. 计算默认总金额
        self.total_amount = sum(p.price for p in self.products)


# -------------------------- 3. 具体原型：电商订单 --------------------------
class EcommerceOrder(OrderPrototype):
    """电商订单具体原型（实现深克隆）"""

    def __init__(self, user_id: str, product_ids: List[str]):
        # 1. 生成唯一订单号（原型初始化时生成，克隆时需重新生成）
        self.order_id = self._generate_order_id()
        # 2. 复杂初始化（仅执行一次）
        self.init_complex_data(user_id, product_ids)
        # 3. 基本属性
        self.user_id = user_id
        self.status = "pending"  # 订单状态（默认待支付）

    def _generate_order_id(self) -> str:
        """生成唯一订单号（UUID）"""
        return f"ORDER-{uuid.uuid4().hex[:12].upper()}"

    def clone(self, **kwargs) -> "EcommerceOrder":
        """
        深克隆实现：
        1. 用deepcopy复制所有成员（包括引用类型）
        2. 修改差异属性（如order_id、user_id、total_amount）
        """
        # 深克隆：复制所有成员（products、address等引用类型会递归复制）
        new_order = copy.deepcopy(self)

        # 修改差异属性（优先级：kwargs中的值 > 原型值）
        new_order.order_id = self._generate_order_id()  # 克隆订单必须生成新订单号
        if "user_id" in kwargs:
            new_order.user_id = kwargs["user_id"]
            # 若用户ID变更，重新查询地址（模拟克隆时的局部更新）
            new_order.address.user_id = kwargs["user_id"]
        if "total_amount" in kwargs:
            new_order.total_amount = kwargs["total_amount"]
        if "status" in kwargs:
            new_order.status = kwargs["status"]

        # 克隆时修改商品库存（验证深克隆：仅影响新订单，不影响原型）
        if "reduce_stock" in kwargs and kwargs["reduce_stock"]:
            for product in new_order.products:
                product.stock -= 1  # 新订单商品库存减1

        return new_order

    def __str__(self):
        products_str = "\n  ".join([str(p) for p in self.products])
        return (
            f"EcommerceOrder(\n"
            f"  order_id={self.order_id},\n"
            f"  user_id={self.user_id},\n"
            f"  total_amount={self.total_amount},\n"
            f"  status={self.status},\n"
            f"  address={self.address},\n"
            f"  products=[\n  {products_str}\n  ]\n"
            f")"
        )


# -------------------------- 4. 客户端使用：批量生成订单 --------------------------
if __name__ == "__main__":
    # 1. 创建原型订单（仅执行一次复杂初始化：查询地址、商品）
    print("=== 创建原型订单 ===")
    prototype_order = EcommerceOrder(
        user_id="user_001",
        product_ids=["p1001", "p1002"]  # 购买iPhone和AirPods
    )
    print(prototype_order)

    # 2. 批量克隆订单（仅修改差异属性，无需重复查询数据）
    print("\n=== 批量克隆订单 ===")
    order1 = prototype_order.clone(
        user_id="user_002",
        total_amount=8798.0,  # 优惠后金额（原价6999+1799=8798）
        reduce_stock=True  # 克隆时减库存
    )
    print("订单1（用户002，减库存）:")
    print(order1)

    order2 = prototype_order.clone(
        user_id="user_003",
        status="paid",  # 直接设置为已支付
        total_amount=8598.0  # 另一个优惠价
    )
    print("\n订单2（用户003，已支付）:")
    print(order2)

    # 3. 验证深克隆：修改新订单的引用类型成员，不影响原型
    print("\n=== 验证深克隆 ===")
    print(f"原型订单商品1库存: {prototype_order.products[0].stock}")  # 原型库存仍为100
    print(f"订单1商品1库存: {order1.products[0].stock}")  # 订单1库存为99（已减1）